#include "stdio.h"
#include "time.h"
#include "stdlib.h"
#include "string.h"
#include "windows.h"
#define dataBufferSize 2
#define processNum 4

typedef struct Seamphore
{
    int value;
    int *pcq;
}Seamphore;

int producerCongestionQueue[processNum];
int consumerCongestionQueue[processNum];
int shareCongestionQueue[processNum];
Seamphore empty={dataBufferSize,producerCongestionQueue};

Seamphore full={0,consumerCongestionQueue};
Seamphore mutex={1,shareCongestionQueue};

struct DataBuffer
{
    int buffer[dataBufferSize];
    int count;
}dataBuffer;

typedef struct Process
{
    char name[10];
    int roleFlag;
    int currentState;
    int currentStep;
    int data;
    int code;
}Process;
Process process[processNum];

void moveDataForward(){
    int i;
    for(i=0;i<dataBuffer.count;i++)
        dataBuffer.buffer[i]=dataBuffer.buffer[i+1];
}

void push(int data){
    dataBuffer.buffer[dataBuffer.count++]=data;
}

int pop()
{
    int data=dataBuffer.buffer[0];
    dataBuffer.count--;
    moveDataForward();
    return data;
}

void initProcess(){
    int i;
    char digitTemp[5];
    srand(time(NULL));
    for(i=0;i<processNum;i++){
        process[i].roleFlag=rand()%2;
    if(process[i].roleFlag)
        strcpy(process[i].name,"生产者");
    else
        strcpy(process[i].name,"消费者");
    strcat(process[i].name,itoa(i+1,digitTemp,10));
        process[i].currentState=1;
        process[i].currentStep=1;
        process[i].code=i+1;
        producerCongestionQueue[i]=0;
        consumerCongestionQueue[i]=0;
        shareCongestionQueue[i]=0;
    }
}

void wakeup(int *pcq){
    int code=pcq[0]-1;
    process[code].currentState=1;
    if(process[code].roleFlag==1){
        if(process[code].currentStep==2){
            printf("%20s: 该进程被唤醒!申请访问空缓冲区成功!\n",
                process[code].name);
        }else if(process[code].currentStep==3){
            printf("%20s: 该进程被唤醒!申请访问缓冲区成功!\n",
                process[code].name);
        }
    }else if(process[code].roleFlag==0){
        if (process[code].currentStep==1)
        {
            process[code].data=pop();
            printf("%20s: 该进程被唤醒!申请取产品%d成功!\n",
                process[code].name,process[code].data);
        }else if(process[code].currentStep==2){
            printf("%20s: 该进程被唤醒!申请访问缓冲区成功!\n",
                process[code].name);
        }
    }
    process[code].currentStep++;
    for(int i=1;(i<processNum)&&(pcq[i]!=0);i++){
        pcq[i-1]=pcq[i];
        if(pcq[i-1]>processNum){
            pcq[i-1]=0;
        }
    }
    int i;
    pcq[i-1]=0;
}

void sleep(int pcq[],int code){
    int i;
    process[code-1].currentState=0;
    for(i=0;i<processNum;i++){
        if(!pcq[i]){
            pcq[i]=code;
            break;
        }
    }
}

void P(Seamphore *s, Process *p){
    s->value-=1;
    if(s->value>=0){
        if(p->roleFlag==1){
            if(p->currentStep==2){
                printf("%20s: 申请空缓冲区成功!\n",p->name);
            }else if(p->currentStep==3){
                printf("%20s: 申请访问缓冲区成功!]n",p->name);
            }
        }else if(p->roleFlag==0){
                if(p->currentStep==1){
                    printf("%20s: 申请取出产品成功!\n",p->name);
                }else if(p->currentStep==2){
                    printf("%20s: 申请访问缓冲区成功!\n",p->name);
                }
            }
            p->currentStep++;
        }else if(s->value<0){
            if(p->roleFlag==1){
                if(p->currentStep==2){
                    printf("%20s: 无空缓冲区，该进程被阻塞!\n",p->name);
                }else if(p->currentStep==3){
                    printf("%20s: 其他进程正在访问缓冲区，该进程被阻塞!\n",p->name);
                }
            }else if(p->roleFlag==0){
                if(p->currentStep==1){
                    printf("%20s: 无产品可取，该进程被阻塞!\n",p->name);
                }else if(p->currentStep==2){
                    printf("%20s: 其他进程正在访问缓冲区，该进程被阻塞!\n",p->name);
                }
            }
            sleep(s->pcq,p->code);
            
        }
}

void V(Seamphore *s,Process *p){
    s->value+=1;
    if(p->roleFlag==1){
        if(p->currentStep==5){
            printf("%20s: 释放缓冲区访问权!\n",p->name);
        }else if(p->currentStep==6){
            printf("%20s: 产品已送入缓冲区,产品数量增加!\n",p->name);
        }
    }else if(p->roleFlag==0){
        if(p->currentStep==4){
            printf("%20s: 释放缓冲区访问权!\n",p->name);
        }else if(p->currentStep==5){
            printf("%20s: 产品已取出,空缓存区数量增加!\n",p->name);
        }
    }
    if(s->value<=0){
        wakeup(s->pcq);
    }
    p->currentStep++;
}


void produce(Process *p){
    switch (p->currentStep)
    {
    case 1:
        p->data=rand()%1000;
        printf("%20s: 生产一个产品%d!\n",p->name,p->data);
        p->currentStep++;
        break;
    case 2:
        P(&empty,p);
        break;
    case 3:
        P(&mutex,p);
        break;
    case 4:
        push(p->data);
        printf("%20s: 将产品%d正送入缓冲区!\n",p->name,p->data);
        p->currentStep++;
        break;
    case 5:
        V(&mutex,p);
        break;
    case 6:
        V(&full,p);
        p->currentStep=1;
        break;
    }
}

void consume(Process *p){
    switch (p->currentStep)
    {
    case 1:
        P(&full,p);
        break;
    case 2:
        P(&mutex,p);
        break;
    case 3:
        p->data=pop();
        printf("%20s: 从缓冲区中正取出产品%d!\n",p->name,p->data);
        p->currentStep++;
        break;
    case 4:
        V(&mutex,p);
        break;
    case 5:
        V(&empty,p);
        break;
    case 6:
        printf("%20s: 消费产品%d!\n",p->name,p->data);
        p->currentStep=1;
        break;
    }
}

void rr(){
    Process *p;
    while (1)
    {
        p=&process[rand()%processNum];
        if(!p->currentState){
            continue;
        }
        if(p->roleFlag){
            produce(p);
        }else{
            consume(p);
        }
        Sleep(100);
    }
    
}

void deal(){
    printf("\t\t生产者-消费者算法模拟\n\n");
    initProcess();
    rr();
}

int main(){
    deal();
    return 0;
}